<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手写apply函数</title>
</head>
<body>
  <script>
    let obj={
      a:2,
      b:3
    }
    function sum(a,b){
      console.log(this.a,this.b,a,b)
    }
    sum(3,4)      // undefined undefined 3 4
    sum.apply(obj,[3,4]) // 2 3 3 4

    // 手写apply函数
    // 1：Function.prototype._apply = function(target){}
    // 2：函数内部先判断，如果target不是对象，且为boolean，number，string，则对应new Boolean(target)，new Number(target)，new String(target)
    // 3：创建一个值fn，let fn = Symbol();，给context添加一个属性，字段为fn，指向调用apply方法的函数context[fn]=this;
    // 4：let args = arguments[1]，args就为传入的数组数据，调用这个函数result = target[fn](...args)
    // 5：删除context[fn]来复原，delete context[fn];
    // 6：最后返回，return result;
    Function.prototype._apply = function(target){
      (target == null || target == undefined) && (target = window);
      if(typeof target !== 'object'){
        if(typeof target == 'number') target = new Number(target)
        if(typeof target == 'boolean') target = new Boolean(target)
        if(typeof target == 'string') target = new String(target)
    }
      let fn = Symbol();
      console.log(fn)
      console.log(this)
      console.log(target)
      target[fn] = this
      console.log(target[fn])
      // arguments就是传进去的参数集合，通过arguments[1]得到传进来的数组参数
      let args = arguments[1]
      let result;
      if(args){
          // 通过...展开运算符将数组参数展开传给函数
          result = target[fn](...args)
      }else{
          // 当args没有值的时候直接调用函数，不传参
          result = target[fn]()
      }
      delete target[fn]
      return result
    }
    sum._apply(obj,[3,4])
  </script>
</body>
</html>